package com.sooth.micro.camunda.converter.processing.gateway;

import cn.hutool.core.collection.CollUtil;
import com.sooth.micro.camunda.converter.bean.BaseDefinition;
import com.sooth.micro.camunda.converter.bean.gateway.BranchNode;
import com.sooth.micro.camunda.converter.bean.gateway.ExclusiveGatewayDefinition;
import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.model.bpmn.builder.AbstractFlowNodeBuilder;
import org.camunda.bpm.model.bpmn.builder.ExclusiveGatewayBuilder;
import org.camunda.bpm.model.bpmn.instance.SequenceFlow;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class ExclusiveGatewayProcessor
        extends AbstractGatewayProcessor<ExclusiveGatewayDefinition, AbstractFlowNodeBuilder> {

    @Override
    public String onComplete(
            AbstractFlowNodeBuilder flowNodeBuilder, ExclusiveGatewayDefinition flowNode)
            throws InvocationTargetException, IllegalAccessException {
        ExclusiveGatewayBuilder exclusiveGatewayBuilder =
                flowNodeBuilder.exclusiveGateway().name(flowNode.getNodeName());

        // create execution listener
        createExecutionListener(exclusiveGatewayBuilder, flowNode);
        List<BranchNode> branchNodes = flowNode.getBranchNodes();
        if (CollUtil.isEmpty(flowNode.getBranchNodes())
                && Objects.isNull(flowNode.getNextNode())) {
            return exclusiveGatewayBuilder.getElement().getId();
        }
        List<String> incoming = new ArrayList<>(branchNodes.size());

        // 不存在任务节点的情况（即空分支: 见 branchNode-2）
        List<BranchNode> emptyNextNodeBranchNodes = new CopyOnWriteArrayList();
        for (BranchNode branchNode : branchNodes) {
            BaseDefinition nextNode = branchNode.getNextNode();

            String nodeName = branchNode.getNodeName();
            String expression = branchNode.getExpression();

            // 记录分支条件中不存在任务节点的情况（即空分支: 见 branchNode-2）
            // ------------------------
            //
            //            --(branchNode-1)--> serviceTask(current) --> serviceTask  --
            // gateway -->                                                            --> gateway(merge)
            // --> serviceTask(nextNode)
            //            --(branchNode-2)-->  -----------------------------------  --
            //
            //
            if (Objects.isNull(nextNode)) {
                incoming.add(exclusiveGatewayBuilder.getElement().getId());
                BranchNode condition = new BranchNode();
                condition.setNodeName(nodeName);
                condition.setExpression(expression);
                emptyNextNodeBranchNodes.add(condition);
                continue;
            }

            // 只生成一个任务，同时设置当前任务的条件
            nextNode.setIncoming(Collections.singletonList(exclusiveGatewayBuilder.getElement().getId()));
            String id =
                    onCreate(
                            moveToNode(exclusiveGatewayBuilder, exclusiveGatewayBuilder.getElement().getId()),
                            nextNode);
            Collection<SequenceFlow> outgoings = exclusiveGatewayBuilder.getElement().getOutgoing();
            SequenceFlow[] sequenceFlows = outgoings.toArray(new SequenceFlow[outgoings.size()]);
            conditionExpression(sequenceFlows[sequenceFlows.length - 1], exclusiveGatewayBuilder, branchNode);
//            exclusiveGatewayBuilder.getElement().getOutgoing().stream()
//                    .forEach(
//                            sequenceFlow ->
//                                    conditionExpression(sequenceFlow, exclusiveGatewayBuilder, branchNode));
            if (Objects.nonNull(id)) {
                incoming.add(id);
            }
        }

        String id = exclusiveGatewayBuilder.getElement().getId();
        BaseDefinition nextNode = flowNode.getNextNode();
        if (Objects.nonNull(nextNode)) {
            nextNode.setIncoming(incoming);
            return merge(exclusiveGatewayBuilder, id, emptyNextNodeBranchNodes, nextNode);
        }
        return id;
    }

    protected void accept(
            AbstractFlowNodeBuilder flowNodeBuilder, String mergeId, List<BranchNode> conditions) {
        if (!(flowNodeBuilder instanceof ExclusiveGatewayBuilder)) {
            return;
        }
        //  针对分支条件中空分支场景 添加条件表达式
        ExclusiveGatewayBuilder exclusiveGatewayBuilder = (ExclusiveGatewayBuilder) flowNodeBuilder;
        if (CollUtil.isNotEmpty(conditions)) {
            List<SequenceFlow> sequenceFlows =
                    moveToNode(exclusiveGatewayBuilder, mergeId).getElement().getIncoming().stream()
                            // 获取从源 gateway 到目标节点 未设置条件表达式的节点
                            .filter(
                                    e ->
                                            StringUtils.equals(
                                                    e.getSource().getId(), exclusiveGatewayBuilder.getElement().getId()))
                            .collect(Collectors.toList());

            sequenceFlows.stream()
                    .forEach(
                            sequenceFlow -> {
                                if (!conditions.isEmpty()) {
                                    BranchNode condition = conditions.get(0);
                                    conditionExpression(sequenceFlow, exclusiveGatewayBuilder, condition);
                                    conditions.remove(0);
                                }
                            });
        }
    }

    private void conditionExpression(
            SequenceFlow sequenceFlow,
            ExclusiveGatewayBuilder exclusiveGatewayBuilder,
            BranchNode condition) {
        if (condition.getIsDefault()) {
            exclusiveGatewayBuilder.defaultFlow(sequenceFlow);
        }
        createConditionExpression(sequenceFlow, exclusiveGatewayBuilder, condition);
    }
}
